package models

import (
	"errors"
	"time"

	"gitee.com/sansaniot/ssiot-core/httpmvc/model"
	"gitee.com/sansaniot/ssiot-core/logger"
	"gorm.io/datatypes"
	"gorm.io/gorm"

	cDto "ssdevice/common/dto"
	"ssdevice/common/utils"
	"ssdevice/internal/device/models/query"
)

type SysDevFunc struct {
	Id           string          `json:"id" gorm:"primaryKey;type:varchar(255);comment:id"`
	DevSn        string          `json:"devSn" gorm:"type:varchar(255);comment:设备序列号"`
	Data         datatypes.JSON  `json:"data" gorm:"type:jsonb;comment:profile.func"`
	Schema       datatypes.JSON  `json:"schema" gorm:"type:jsonb;comment:func schema信息"`
	CreateTime   *cDto.LocalTime `json:"createTime" gorm:"type:timestamptz(6);comment:创建时间"`
	UpdateTime   *cDto.LocalTime `json:"updateTime" gorm:"type:timestamptz(6);comment:更新时间"`
	ProductModel string          `json:"productModel" gorm:"type:varchar(255);comment:产品编码"`
	DevProductId string          `json:"devProductId" gorm:"type:varchar(255);comment:产品Id"`

	model.Model
}

func (SysDevFunc) TableName() string {
	return "sys_dev_func"
}

func (e *SysDevFunc) Generate() interface{} {
	o := *e
	return &o
}

func (e *SysDevFunc) GetId() interface{} {
	return e.Id
}

func (e *SysDevFunc) FindDevConfig(req *query.SysDevFuncQuery) error {
	return e.FindOne(e, cDto.MakeCondition(req.GetNeedSearch()))
}

func (e *SysDevFunc) UpdateDevFunc(sn string, data map[string]interface{}) error {
	t1 := time.Now()
	dataBytes := utils.MapToBytes(data)
	dataMap := utils.BytesToMap(dataBytes)

	df := SysDevFunc{}
	if err := e.FindOne(&df, cDto.MakeCondition(query.SysDevFuncQuery{Sn: sn})); err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return err
	}
	dm := map[string]interface{}{"func": dataMap}
	if len(df.Id) > 0 {
		// 合并
		utils.DeepMerge(utils.BytesToMap(df.Data), dm)
		shcemaMap := utils.GetObjectSchema(dm)["properties"].(map[string]interface{})
		utils.DeepMerge(utils.BytesToMap(df.Schema), shcemaMap)
		df.Data = utils.MapToBytes(dm)
		df.Schema = utils.MapToBytes(shcemaMap)
	} else {
		// 新建
		now := cDto.LocalTime(t1)
		df = SysDevFunc{
			Id:         utils.SimpleUUID(),
			DevSn:      sn,
			Data:       utils.MapToBytes(dm),
			Schema:     utils.MapToBytes(utils.GetObjectSchema(dm)["properties"].(map[string]interface{})),
			CreateTime: &now,
			UpdateTime: &now,
		}
	}
	if err := e.Upsert(&df); err != nil {
		return err
	}
	logger.Infof("func模型更新. 耗时%v", time.Since(t1).Round(time.Millisecond))
	return nil
}
